//
//  CommonAPI.m
//  ClinicalCollections
//
//  Created by janakiraman gopinath on 2/1/13.
//  Copyright (c) 2013 GOPI. All rights reserved.
//

#import "CommonAPI.h"


static  NSMutableSet *recents;

@implementation CommonAPI

+ (id) targetViewControllerFrom:(id)viewController
                        forPath:(enum PATH_FOR_TAB_VIEW_CONTROLLER) path
                           side:(enum LEFT_OR_RIGHT) leftOrRight
        returningViewController:(enum VIEW_CONTROLLER) targetViewController
{
    
    id vc = [[[viewController splitViewController] viewControllers] objectAtIndex:leftOrRight];
    int vcDepth = [[vc viewControllers] count];
    
    switch (leftOrRight) {
        case LEFT: {
            UITabBarController  *tabBarController = (UITabBarController *) vc;
            
            UINavigationController *navigationController;
            
            // Tab bar controller ClinicalTrial.gov
            // Look at the story board to understand this code better
            if (path == CLINICALTRIALGOV)
                navigationController = [[tabBarController viewControllers] objectAtIndex:0];
            // Tab bar contoller CLinical Trial Catalog
            else if (path == CLINICALTRIALCATALOG)
                navigationController = [[tabBarController viewControllers] objectAtIndex:1];
            
            if (targetViewController == GENERICVIEWCONTROLLER)
                return [[navigationController viewControllers] lastObject];
            else if (targetViewController == SEARCHVIEWCONTROLLER)
                return [[navigationController viewControllers] objectAtIndex:0];
            else
                return nil;
            break;
        }
        case RIGHT:
            //fix: prevent nsrange exceptions
            if (targetViewController == CLINICALCOLLECTIONSVIEWCONTROLLER)
                return [[vc viewControllers] objectAtIndex:0];
            else if (vcDepth > 1 && (targetViewController == GRAPHVIEWCONTROLLER ||
                                     targetViewController == CLINICALTRIALWEBVIEWCONTROLLER ||
                                     targetViewController == CCVIEWSTUDYVIEWCONTROLLER))
                return [[vc viewControllers] objectAtIndex:1];
            else
                return nil;
            
        default:
            break;
    }
    return nil;
}

+ (NSSet *) getRecents
{
    if (!recents || recents == nil || ![recents count]) {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSData *data = [defaults objectForKey:NCTID];
        NSSet *set = [NSKeyedUnarchiver unarchiveObjectWithData:data];
        recents = [[NSMutableSet alloc] initWithSet:set];
    }
    return recents;
}
+ (void) addRecents:(NSString *) nctId
             search:(NSString *) searchString
{
    (void) [self getRecents];
    
    [recents addObject:[NSString stringWithFormat:@"%@,%@",nctId, searchString]];
    if ([recents count] > DEFAULTS_COUNT)
        [recents removeObject:[[recents allObjects] objectAtIndex:0]];
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:recents];
    [defaults setObject:data forKey:NCTID];
    [defaults synchronize];
}
+ (void) removeRecentsSearchString:(NSString *) searchString
{
    NSArray *array = [recents allObjects];
    for (int i = 0; i < array.count; i++)
        if ([[[array[i] componentsSeparatedByString:@","] lastObject] isEqualToString:searchString])
            [recents removeObject:array[i]];
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:recents];
    [defaults setObject:data forKey:NCTID];
    [defaults synchronize];
}
+ (void) removeRecentsNCTID:(NSString *) nctID
{
    NSArray *array = [recents allObjects];
    for (int i = 0; i < array.count; i++)
        if ([[[array[i] componentsSeparatedByString:@","] objectAtIndex:0] isEqualToString:nctID])
            [recents removeObject:array[i]];
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:recents];
    [defaults setObject:data forKey:NCTID];
    [defaults synchronize];
}

+ (NSDictionary *) searchData:(Search *) search
                   searchText:(NSString *) searchText
{
    NSArray *cts = [search.clinicalTrialGov allObjects];
    NSMutableArray *searchListClinicalTrialGov = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListConditions = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListGroups = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListMeasure = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListLocation = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListIntervention = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListOtherNames = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListOutcomes = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListArmGroups = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListArmgroupLabel = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListEligibility = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListStudyType = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListStudyDesign = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableArray *searchListPhase = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    NSMutableDictionary *searchListDict = [[NSMutableDictionary alloc] initWithCapacity:MAX_CAPACITY];
    
    
    NSDictionary *searchList;
    
    for (ClinicalTrialGov *ct in cts) {
        
        // Search Clinical Trial Base object for potential Hits 
        if ([[CommonAPI class] searchTextInString:ct.nctID
                                       searchText:searchText] ||
            [[CommonAPI class] searchTextInString:ct.status
                                       searchText:searchText] ||
            [[CommonAPI class] searchTextInString:ct.briefTitle
                                       searchText:searchText] ||
            [[CommonAPI class] searchTextInString:ct.city
                                       searchText:searchText]) {
                [searchListClinicalTrialGov addObject:ct.nctID];
            }
        if ([searchListClinicalTrialGov count] >  0)
            [searchListDict setObject:searchListClinicalTrialGov forKey:CLINICAL_TRIAL_GOV_HITS];
        
        if ([[CommonAPI class] searchTextInString:ct.study_type
                                       searchText:searchText]) {
            [searchListStudyType addObject:ct.nctID];
        }
        if ([searchListStudyType count] >  0)
            [searchListDict setObject:searchListStudyType forKey:STUDY_TYPE_HITS];
        
        if ([[CommonAPI class] searchTextInString:ct.study_design
                                       searchText:searchText]) {
            [searchListStudyDesign addObject:ct.nctID];
        }
        if ([searchListStudyDesign count] >  0)
            [searchListDict setObject:searchListStudyDesign forKey:STUDY_DESIGN_HITS];
        
        
        if ([[CommonAPI class] searchTextInString:ct.phase
                                       searchText:searchText]) {
            [searchListPhase addObject:ct.nctID];
        }
        if ([searchListPhase count] >  0)
            [searchListDict setObject:searchListPhase forKey:PHASE_HITS];

        // Search Condition Object for possible hits
        NSArray *eligibilities = [ct.eligibility allObjects];
        
        for (Eligibility *eligibility in eligibilities) {
            if ([[CommonAPI class] searchTextInString:eligibility.criteria                                           searchText:searchText] ||
                [[CommonAPI class] searchTextInString:eligibility.gender                                           searchText:searchText] ) {
                [searchListEligibility addObject:ct.nctID];
                break;
            }
        }
        if ([searchListEligibility count] >  0)
            [searchListDict setObject:searchListEligibility forKey:ELIGIBILITY_HITS];

        
        // Search Condition Object for possible hits
        NSArray *conditions = [ct.condition allObjects];

        for (Condition *condition in conditions) {
            if ([[CommonAPI class] searchTextInString:condition.condition                                           searchText:searchText]) {
                [searchListConditions addObject:ct.nctID];
                break;
            }
        }
        if ([searchListConditions count] >  0)
            [searchListDict setObject:searchListConditions forKey:CONDITIONS_HITS];
        
        // Search city for potential Hits 
        NSArray *locations = [ct.location allObjects];
        
        for (Location *location in locations) {
            if ([[CommonAPI class] searchTextInString:location.city searchText:searchText]) {
                [searchListLocation addObject:ct.nctID];
                break;
            }
        }
        if ([searchListLocation count] >  0)
            [searchListDict setObject:searchListLocation    forKey:LOCATION_HITS];
        
        // Search Outcomes for potential Hits
        
        NSArray *outcomes = [ct.outcome allObjects];
        for (Outcome *outcome in outcomes) {
            if ([[CommonAPI class] searchTextInString:outcome.desc searchText:searchText]) {
                [searchListOutcomes addObject:ct.nctID];
                break;
            }
            if ([[CommonAPI class] searchTextInString:outcome.type searchText:searchText]) {
                [searchListOutcomes addObject:ct.nctID];
                break;
            }
            if ([[CommonAPI class] searchTextInString:outcome.safety_issues searchText:searchText]) {
                [searchListOutcomes addObject:ct.nctID];
                break;
            }
            if ([[CommonAPI class] searchTextInString:outcome.time_frame searchText:searchText]) {
                [searchListOutcomes addObject:ct.nctID];
                break;
            }
        }
        if ([searchListOutcomes count] >  0)
            [searchListDict setObject:searchListOutcomes    forKey:OUTCOME_HITS];
        
        // Search Interventions, OtherName &
        // ArmGroupLabel for potential hits
        
        NSArray *interventions = [ct.intervention allObjects];
        BOOL otherNameFlag = NO;
        BOOL armGroupLabelFlag = NO;
        for (Intervention *intervention in interventions) {
            
            NSArray *otherNames = [intervention.otherName allObjects];
            if (!otherNameFlag)
                for (OtherName *otherName in otherNames)
                    if ([[CommonAPI class] searchTextInString:otherName.name
                                                   searchText:searchText]) {
                        [searchListOtherNames addObject:ct.nctID];
                        otherNameFlag = YES;
                        break;
                    }
            NSArray *armGroupLabels = [intervention.armGroupLabel allObjects];
            if (!armGroupLabelFlag)
                for (ArmGroupLabel *armGroupLabel in armGroupLabels)
                    if ([[CommonAPI class] searchTextInString:armGroupLabel.name
                                                   searchText:searchText]) {
                        [searchListArmgroupLabel addObject:ct.nctID];
                        armGroupLabelFlag = YES;
                        break;
                    }

            if ([[CommonAPI class] searchTextInString:intervention.desc
                                           searchText:searchText] ||
                [[CommonAPI class] searchTextInString:intervention.name
                                           searchText:searchText] ||
                [[CommonAPI class] searchTextInString:intervention.type
                                           searchText:searchText]) {
                    [searchListIntervention addObject:ct.nctID];
                    break;
                }
        }
        if ([searchListIntervention count] >  0)
            [searchListDict setObject:searchListIntervention forKey:INTERVENTION_HITS];
        if ([searchListOtherNames count] >  0)
            [searchListDict setObject:searchListOtherNames forKey:OTHER_NAME_HITS];
        if ([searchListArmgroupLabel count] >  0)
            [searchListDict setObject:searchListArmgroupLabel forKey:ARM_GROUP_LABEL_HITS];

        // Search Arm Groups for hits
        // 
        NSArray *armGroups = [ct.armGroups allObjects];
        for (ArmGroups *armGroup in armGroups) {
            if ([[CommonAPI class] searchTextInString:armGroup.desc
                                           searchText:searchText] ||
                [[CommonAPI class] searchTextInString:armGroup.arm_group_label
                                           searchText:searchText] ||
                [[CommonAPI class] searchTextInString:armGroup.arm_group_type
                                           searchText:searchText]) {
                    [searchListArmGroups addObject:ct.nctID];
                    break;
                }
        }
        if ([searchListArmGroups count] >  0)
            [searchListDict setObject:searchListArmGroups forKey:ARM_GROUP_HITS];
        
        NSArray *groups = [ct.groups allObjects];
        for (Groups *group in groups) {
            if ([[CommonAPI class] searchTextInString:group.title
                                           searchText:searchText] ||
                [[CommonAPI class] searchTextInString:group.type
                                           searchText:searchText]) {
                    [searchListGroups addObject:ct.nctID];
                    break;
                }
        }
        if ([searchListGroups count] >  0)
            [searchListDict setObject:searchListGroups forKey:GROUPS_HITS];
        // Search the data for hits up to measures 
        BOOL eos = NO;
        for (GroupTypes *groupType in [ct.groupTypes allObjects]) {
            eos = NO;
            for (Measure *measure in [groupType.measure allObjects]) {
                if ([[CommonAPI class] searchTextInString:measure.title
                                               searchText:searchText]) {
                    [searchListMeasure addObject:ct.nctID];
                    eos = YES;
                    break;
                }
            }
            if (eos) break;
        }
    }
    searchList = [[NSDictionary alloc] initWithDictionary:searchListDict];
    return searchList;
    
}
#pragma mark -- Util functions

+ (void) mergeArray:(NSMutableArray *) baseArray
          withArray:(NSArray *) arrays
{
    for (NSArray *array in arrays)
        [baseArray addObject:array];
}

+ (NSArray *) createAnnotations:(NSArray *)array
              primaryAnnotation:(BOOL) primary
               accessoryEnabled:(BOOL) accessory
                          title:(NSString *) title
{
    NSMutableArray *annotationArray = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    
    for (int i = 0; i < array.count; i++) {
        ClinicalAnnotation *clinicalAnnotation = [[ClinicalAnnotation alloc] init];
        CLLocationCoordinate2D coordinate;
        
        if ([array[i] respondsToSelector:@selector(nctID)])
            clinicalAnnotation.title = [array[i] nctID];
        else
            clinicalAnnotation.title = title;
        
        if ([array[i] respondsToSelector:@selector(city)])
            clinicalAnnotation.subTitile = [array[i] city];//MC is this a typo? SubTitile vs subtitle
        
        coordinate.latitude = [[array[i] lat] doubleValue];
        coordinate.longitude = [[array[i] lng] doubleValue];
        clinicalAnnotation.coordinate = coordinate;
        clinicalAnnotation.primary = primary;
        clinicalAnnotation.noAccessory = !accessory;
        clinicalAnnotation.hasAnalytics = NO; // by default, do not show the analytics accessory
        
        if ([array[i] respondsToSelector:@selector(groupTypes)]){
            // Fix MC -- copied this logic from GenericTableViewController.m in order to
            //           only display the analytics accessory when there is data
            // Check the noOfParticipants sometimes groups does have data and no_of_participants
            // This will end up creating a blank graph
            clinicalAnnotation.hasAnalytics = [CommonAPI doesStudyContainAnalytics:array[i]];
            //            if ([[[[[array[i] groupTypes] allObjects] objectAtIndex:0] measure] count] > 0 &&
            //                ![[array[i] groupTypes ] isEqual:[NSNull null]]) {
            //                clinicalAnnotation.hasAnalytics = YES;
            //            }
        }
        [annotationArray addObject:clinicalAnnotation];
    }
    return annotationArray;
}

+(BOOL)doesStudyContainAnalytics:(ClinicalTrialGov*)clinicalTrialGov
{
    BOOL retval = NO;
    if ([[[[clinicalTrialGov.groupTypes allObjects] objectAtIndex:0] measure] count] > 0 && ![clinicalTrialGov.groupTypes isEqual:[NSNull null]]) {
        retval = YES;
    }
    return retval;
}

+ (ClinicalTrialGov *) clinicalTrialGov:(NSString *) nctId
                             fromSearch:(Search *) search
{
    NSArray *clinicalTrialGovArray = [search.clinicalTrialGov allObjects];
    
    for (ClinicalTrialGov *clinGov in clinicalTrialGovArray)
        if ([clinGov.nctID isEqualToString:nctId])
            return clinGov;
    return nil;
}
+(void)download:(void (^)())block {
    dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL);
    dispatch_async(downloadQueue, block);
}

+(void)main:(void (^)())block {
    dispatch_async(dispatch_get_main_queue(), block);
}

+ (id) getObjectFromSet:(NSArray *) array
              forObject:(id) object
               forIndex:(int) index
{
    switch (index) {
        case 0:
        {
            for (id Object in array[index])
                if ([Object isEqual:object])
                    return Object;
            break;
        }
        case 1:
        {
            NSDictionary *dict = array[index];
            return [dict valueForKey:object];
            break;
        }
        default:
            break;
    }
    return nil;
}
+ (BOOL) checkGraphHostinView:(CPTPlot *) plot
                  hostingView:(CPTGraphHostingView *) hostingView
{
    if([[plot.graph hostingView] isEqual:hostingView])
        return YES;
    else
        return NO;
}

+ (void) removeImageViewFromCell:(UITableViewCell *) cell
{
    NSArray *uiViews = [cell subviews];
    
    for (int i = 0; i < uiViews.count; i++)
        if ([uiViews[i] isKindOfClass:[UIImageView class]])
            [uiViews[i] removeFromSuperview];
}


#pragma mark -- Load from Clinical Trial gov structure into NSArray for COREPLOT



// Core plot helper routines

+ (NSArray *) getCategorySubtitle:(ClinicalTrialGov *) clinicalTrialGov
                        groupType:(NSString *) type
                     measureTitle:(NSString *) measureTitle
{
    GroupTypes  *groupType;
    for (GroupTypes *groupTypes in [clinicalTrialGov.groupTypes allObjects])
        if ([groupTypes.type isEqual:type]) {
            groupType = groupTypes;
            break;
        }
    NSMutableArray *resultsArray = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    
    for (Measure *measure in groupType.measure) {
        
        if (measureTitle != nil && ![measure.title isEqual:measureTitle]) continue;
        
        NSArray *categories = [measure.categories allObjects];
        
        for (Categories *category in categories)
            if (category.subtitle != nil && ![category.subtitle isEqual:[NSNull null]])
                [resultsArray addObject:category.subtitle];
    }
    return resultsArray;
}

+ (NSArray *) getOutcomes:(ClinicalTrialGov *) clinicalTrialGov
{
    
    NSMutableArray *outcomes = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    
    for (GroupTypes *outcome in [clinicalTrialGov.groupTypes allObjects]) {
        if ([outcome.type hasPrefix:@"outcome"]) {
            [outcomes addObject:outcome];
        }
    }
    return outcomes;
}

+ (NSArray *) loadData:(ClinicalTrialGov *) clinicalTrialGov
             groupType:(NSString *) type
          measureTitle:mTitle
           measureUnit:(NSString *) unit
         categoryTitle:(NSString *) categoryTitle
      categorySubtitle:(NSString *) categorySubTitle
{
    NSMutableArray *participantArray = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    
    // Get baseline value
    GroupTypes  *groupType;
    for (GroupTypes *groupTypes in [clinicalTrialGov.groupTypes allObjects])
        if ([groupTypes.type isEqual:type]) {
            groupType = groupTypes;
            break;
        }
    
    
    // Get measure for Participants
    for (Measure *measures in [groupType.measure allObjects]) {
        
        if ([measures.title isEqual:mTitle] &&
            (unit == nil || (unit != nil && [measures.unit isEqual:unit]))
            ) {
            NSArray *categories = [measures.categories allObjects];
            
            for (Categories *category in categories) {
                if ((categoryTitle != nil && ![category.title isEqual:categoryTitle]) ||
                    (categorySubTitle != nil && ![category.subtitle isEqual:categorySubTitle])
                    )
                    continue;
                NSArray *values = [category.values allObjects];
                
                for (Values *value in values) {
                    NSDictionary *nsDict = [[NSDictionary alloc] initWithObjectsAndKeys:value.value, value.groups.title, nil];
                    [participantArray addObject:nsDict];
                }
            }
        }
    }
    
    return participantArray;
}

+ (NSString *) getGroup:(int) index
         graphDataArray:(NSArray *) array
{
    NSArray *dictArray = [[array objectAtIndex:index] allKeys];
    NSString * result;
    
    if ([dictArray count]) {
        result = dictArray[0];
    } else {
        result = @"";
    }
    return result;
}

+ (NSNumber *) getValue:(int) index
         graphDataArray:(NSArray *) array
{
    NSArray *dictArray = [[array objectAtIndex:index] allKeys];
    
    NSNumber * result;
    if ([dictArray count]) {
        result = (NSNumber *)[[array objectAtIndex:index] objectForKey:dictArray[0]];
    } else {
        result = [NSNumber numberWithInt:0];
    }
    return result;
    
}
+(NSAttributedString *) getNameValueAttributedString:(NSArray *) array
                                               title:(NSString *) title
{
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];
    
    for (int i = 0; i < array.count;i++) {
        if(!i)
            attributedText = [NSString stringWithFormat:@"%@\n%@=%@", title, [[self class] getGroup:i graphDataArray:array],[[self class] getValue:i graphDataArray:array]];
        else if (i == (array.count -1))
            attributedText = [NSString stringWithFormat:@"%@\n%@=%@\n\n", attributedText, [[self class] getGroup:i graphDataArray:array],[[self class] getValue:i graphDataArray:array]];
        else
            attributedText = [NSString stringWithFormat:@"%@\n%@=%@", attributedText, [[self class] getGroup:i graphDataArray:array],[[self class] getValue:i graphDataArray:array]];
    }
    
    return attributedText;
}

+(NSMutableArray *) addkey:(NSString *) key
                  keyValue:(id) keyValue
   toDictionaryObjectArray:(NSArray *) dictArray
{
    NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:MAX_CAPACITY];
    
    if (dictArray == nil || [dictArray isEqual:[NSNull null]])
        return nil;
    else
        for (int i = 0; i < dictArray.count ; i++) {
            NSMutableDictionary *dict = [dictArray[i] mutableCopy];
            [dict setObject:keyValue forKey:key];
            [tempArray addObject:dict];
        }
    return tempArray;
    
}
+(BOOL) searchTextInString:(NSString *) string
                searchText:(NSString *) searchText
{
    
    if (!string || string == nil || [string isEqual:[NSNull null]]) {
        return NO;
    }
    NSComparisonResult result = [string compare:searchText
                                        options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)
                                          range:NSMakeRange(0, [searchText length])];
    if (result == NSOrderedSame)
        return YES;
    
    else
        return NO;
    
}

+ (void) clearKeyboardAndSearchText:(id) viewController
{
    UIViewController *vc = (UIViewController *) (viewController);
    
    [vc.navigationItem.titleView resignFirstResponder];
    ((UISearchBar *)vc.navigationItem.titleView).text = @"";
    
}

+ (void) setupNotification:(NSString *) notificationName
                       for:(id) identifer
                  selector:(SEL) selector
{
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    
    [notificationCenter addObserver:identifer selector:selector name:notificationName object:nil];
}

+ (void) sendNotification:(NSString *) notificationName
              usingObject:(id) object
{
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter postNotificationName:notificationName object:object];
}
+ (void) removeNotification:(NSString *) notificationName
                        for:(id) identifer
{
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter removeObserver:identifer];
}
@end
